#ifndef __INI_CATEGORY_H__
  #define __INI_CATEGORY_H__

#include <string>

#include "macros.h"
#include "converter.h"
#include "unordered_map.h"

using namespace std;

//! A class which represents an ini category

/*!
This class will be mainly used by ini class but you can use it to build an ini file programmatically as well.

Implementation date: 2008

Usage:

\code
ini_category ic;
ic.set_category_name("cat1");
ic.add_item("item1", "value1");

ini i;
i.add_category(ic);
i.to_file("my_ini_file.ini");
\endcode
*/

class ini_category {
private:
  unordered_map<string, string> items; // we don't use map, becuase we need the order
  string category_name;

public:
  //! clears all items of the category, it doesn't change the category name
  void clear() {
    items.clear();
  }

  //! returns the number of items in this category
  size_t get_items_count() const {
    return items.size();
  }

  //! adds a new item to this category
  void add_item(string item_name, string item_value, bool trim = true) {
    if (trim == true) {
      converter::trim(item_name);
      converter::trim(item_value);
    }

    if (items.find(item_name) != SIZE_MAX) {
      string msg = "Item '%1' is not unique within the category '%2'!";
      str::format(msg, arg<string>(item_name, category_name));
      throw ini_exception(msg);
    }

    items.insert(item_name, item_value);
  }

  //! removes the given item from this category. if the item does not exist, then this function will return false
  bool remove_item(const string &item_name) {
    return items.remove(item_name);
  }

  //! returns the name of this category
  const string &get_category_name() const {
    return category_name;
  }

  //! sets the name of this category
  void set_category_name(const string &category_name, bool trim = true) {
    this->category_name = category_name;
    if (trim == true)
      converter::trim(this->category_name);
  }

  //! returns the value of the given key within this category
  const string &get_value(const string &key) const {
    return items[items.find(key)];
  }

  //! returns the string representation of this category
  string &to_string(string &output) const {
    output = '[';
    output += category_name;
    output += "]\n";

    const size_t len = items.size();
    for (size_t i = 0; i < len; ++i) {
      output += items.get_key(i);
      output += '=';
      output += items[i];
      output += '\n';
    } // for i

    return output;
  }

  //! default constructor
  ini_category() {
    // nothing to do
  }

  //! destructor
  virtual ~ini_category() {
    // nothing to do
  }
};

#endif
